/******************************************************************************
**
**                      (C)2023 Ninebot Limited
**
**                         All Right Reserved
**
** 1 tab == 4 spaces!
******************************************************************************/

#ifndef __MACRO_MATH_H_
#define __MACRO_MATH_H_

/*
 * min()/max()/clamp() macros that also do
 * strict type-checking.. See the
 * "unnecessary" pointer comparison.
 */
#define min(x, y)                                             \
	({                                                        \
		__typeof__(x) _min1 = (x);                            \
		__typeof__(y) _min2 = (y);                            \
		(void)((unsigned int)&_min1 == (unsigned int)&_min2); \
		_min1 < _min2 ? _min1 : _min2;                        \
	})

#define max(x, y)                                             \
	({                                                        \
		__typeof__(x) _max1 = (x);                            \
		__typeof__(y) _max2 = (y);                            \
		(void)((unsigned int)&_max1 == (unsigned int)&_max2); \
		_max1 > _max2 ? _max1 : _max2;                        \
	})

/**
 * abs - return absolute value of an argument
 * @x: the value.  If it is unsigned type, it is converted to signed type first.
 *     char is treated as if it was signed (regardless of whether it really is)
 *     but the macro's return type is preserved as char.
 *
 * Return: an absolute value of x.
 */
#define abs(x)                                                                                                      \
	__abs_choose_expr(                                                                                              \
		x, long long,                                                                                               \
		__abs_choose_expr(                                                                                          \
			x, long,                                                                                                \
			__abs_choose_expr(                                                                                      \
				x, int,                                                                                             \
				__abs_choose_expr(x, short,                                                                         \
								  __abs_choose_expr(x, char,                                                        \
													__builtin_choose_expr(                                          \
														__builtin_types_compatible_p(__typeof__(x), char), (char)({ \
															signed char __x = (x);                                  \
															__x < 0 ? -__x : __x;                                   \
														}),                                                         \
														((void)0)))))))

#define __abs_choose_expr(x, type, other)                                                 \
	__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(x), signed type) ||     \
							  __builtin_types_compatible_p(__typeof__(x), unsigned type), \
						  ({                                                              \
							  signed type __x = (x);                                      \
							  __x < 0 ? -__x : __x;                                       \
						  }),                                                             \
						  other)

#define clamp(val, lo, hi) min((__typeof__(val))max(val, lo), hi)

#define do_div(n, base)                   \
	({                                    \
		uint32_t __base = (base);         \
		uint32_t __rem;                   \
		__rem = ((uint64_t)(n)) % __base; \
		(n) = ((uint64_t)(n)) / __base;   \
		__rem;                            \
	})

#endif /* __MACRO_MATH_H_ */
